package TrafficControlSystem.TrafficSimulator;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.Semaphore;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

import TrafficControlSystem.Common.Car;
import TrafficControlSystem.Common.CarsInfo;
import TrafficControlSystem.Common.Direction;
import TrafficControlSystem.Common.GETLIGHTSRequest;
import TrafficControlSystem.Common.GETLIGHTSResponse;
import TrafficControlSystem.Common.IntensityInfo;
import TrafficControlSystem.Common.Light;
import TrafficControlSystem.Common.LightsInfo.LightsState;
import TrafficControlSystem.Common.OKResponse;
import TrafficControlSystem.Common.Response;
import TrafficControlSystem.Common.SETCARSRequest;
import TrafficControlSystem.Common.SETINTENSITYRequest;

public class WorldMap extends JPanel implements ActionListener
{

	private final int PORT_NUMBER = 5001;
	private String addressIp = new String("127.0.0.1");
	private final MyFrame myFrame;
	
	private final Semaphore available = new Semaphore(1);

	/** socket, przez ktory klient bedzie komunikowal sie z serwerem */
	private Socket clientSocket;
	/** Watek odbierajacy zdarzenia od kontrolera i wywolujacy odpowiednie akcje */
	private Thread readerThread;

	public final int SIZE = 46;
	public final int NR_CROSSING = 9;
	private Car carTable[][] = null;
	private Crossing crossingTable[] = null;
	private ArrayList<Car> cars = null;
	private int intensityTable[][] =  new int[NR_CROSSING][2];

	private JButton connectButton = new JButton("connect");
//	private JButton startButton = new JButton("start");
	private JButton moveButton = new JButton("move");
	private JButton buttons[][] = new JButton[4][3];

	private Timer timer = new Timer(180, this);
	private Timer timerSamochody = new Timer(1700, this);

	private boolean onTheRoad(int pos)
	{
		return (pos % (10 + 2)) > 9;
	}

	//eventy timerow
	public void actionPerformed(ActionEvent e)
	{
		if (e.getSource().equals(timer))
		{
			System.out.println("timer1");
			nextMove();
			timer.restart();
		}
		if (e.getSource().equals(timerSamochody))
		{
			System.out.println("timer samochodowy");
			addCars(60);
			timerSamochody.restart();
		}
	}

	/**
	 * Swiat n na n gdy n=46
	 * 
	 * @param n
	 */
	public WorldMap(final MyFrame f)
	{
		this.myFrame = f;
		this.setLayout(null);
		setBorder(BorderFactory.createLineBorder(Color.black));
		this.setPreferredSize(new Dimension(700, 560));
		// przyciski do dodawania recznego samochodow------------
		int ktory = 0;
		int ktory1 = 0;
		for (int j = 0; j < 46; j++)
		{
			if (onTheRoad(j))
			{
//				buttons[ktory][ktory1] = new JButton("("
//						+ Integer.toString(ktory) + ","
//						+ Integer.toString(ktory1) + ")");
				buttons[ktory][ktory1] = new JButton("+");
				buttons[ktory][ktory1].setBounds(35 + j * 10, 0, 50, 50);
				buttons[ktory][ktory1].addActionListener(new ButtonListener());
				this.add(buttons[ktory][ktory1]);

				ktory1++;
				j++;
			}
		}
		ktory++;

		ktory1 = 0;
		for (int j = 0; j < 46; j++)
		{
			if (onTheRoad(j))
			{
//				buttons[ktory][ktory1] = new JButton("("
//						+ Integer.toString(ktory) + ","
//						+ Integer.toString(ktory1) + ")");
				buttons[ktory][ktory1] = new JButton("+");
				buttons[ktory][ktory1].setBounds(35 + j * 10, 510, 50, 50);
				buttons[ktory][ktory1].addActionListener(new ButtonListener());
				this.add(buttons[ktory][ktory1]);
				ktory1++;
				j++;
			}
		}
		ktory++;

		ktory1 = 0;
		for (int j = 0; j < 46; j++)
		{
			if (onTheRoad(j))
			{
//				buttons[ktory][ktory1] = new JButton("("
//						+ Integer.toString(ktory) + ","
//						+ Integer.toString(ktory1) + ")");
				buttons[ktory][ktory1] = new JButton("+");
				buttons[ktory][ktory1].setBounds(0, 35 + j * 10, 50, 50);
				buttons[ktory][ktory1].addActionListener(new ButtonListener());
				this.add(buttons[ktory][ktory1]);
				ktory1++;
				j++;
			}
		}
		ktory++;

		ktory1 = 0;
		for (int j = 0; j < 46; j++)
		{
			if (onTheRoad(j))
			{
//				buttons[ktory][ktory1] = new JButton("("
//						+ Integer.toString(ktory) + ","
//						+ Integer.toString(ktory1) + ")");
				buttons[ktory][ktory1] = new JButton("+");
				buttons[ktory][ktory1].setBounds(510, 35 + j * 10, 50, 50);
				buttons[ktory][ktory1].addActionListener(new ButtonListener());
				this.add(buttons[ktory][ktory1]);
				ktory1++;
				j++;
			}
		}
		// przyciski dodawania
		// samochodow-------------------------------------------

//		startButton.setBounds(650, 215, 100, 50);
//		this.add(startButton);
//		startButton.addActionListener(new ActionListener()
//		{
//			@Override
//			public void actionPerformed(ActionEvent e)
//			{
//				// System.out.println("move1");
//				// nextMove();
//				timer.start();
//				timerSamochody.start();
//				// symulacja(1);
//			}
//		});
		
		moveButton.setBounds(550,460,100,50);
		this.add(moveButton);
		moveButton.addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent e)
			{
				try
				{
					available.acquire();
				}
				catch (InterruptedException e1)
				{
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				nextMove();
				updateIntensity();
				available.release();
			}
		});

		connectButton.setBounds(550, 50, 100, 50);
		this.add(connectButton);
		connectButton.addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent e)
			{
				
				String hostAddress = (String)JOptionPane.showInputDialog(myFrame
						, "podaj adres serwera", "address window",
                        JOptionPane.QUESTION_MESSAGE, null, null,
                        "127.0.0.1");
				addressIp = hostAddress;
				System.out.println("adres serwera:"+addressIp);
				
				// tutaj zrobic connect
				System.out.println("listener connect");
				try
				{
					connectToServer(addressIp);
				}
				catch (UnknownHostException e1)
				{
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				catch (IOException e1)
				{
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		});

		carTable = new Car[SIZE][SIZE];
		crossingTable = new Crossing[NR_CROSSING];
		cars = new ArrayList<Car>();

		// tworzenie skrzyzowan w odpowiednich punktach
		int ktore = 0;
		for (int y = 0; y < SIZE; ++y)
		{
			for (int x = 0; x < SIZE; ++x)
			{
				if (onTheRoad(x) && onTheRoad(y) && onTheRoad(x + 1)
						&& onTheRoad(y + 1))
				{
					crossingTable[ktore] = new Crossing(x, x + 1, y, y + 1);
					System.out.println("skrzyzowanie nr:" + ktore
							+ " , indexy: " + x + "," + (x + 1) + " oraz y: "
							+ y + "," + (y + 1));
					ktore++;
				}
			}
		}

		// dodawanie samochodow do planszy
		// carTable[10][0] = new Car(10, 0, Direction.DOWN);
		// cars.add(carTable[10][0]);
		// carTable[22][0] = new Car(22, 0, Direction.DOWN);
		// cars.add(carTable[22][0]);
		// carTable[23][43] = new Car(23, 43, Direction.UP);
		// cars.add(carTable[23][43]);
		carTable[38][10] = new Car(38, 10, Direction.LEFT);
		cars.add(carTable[38][10]);

		System.out.println("wielkosc tablicy skrzyzowan: "
				+ crossingTable.length);

	}

	private void symulacja(int n)
	{
		System.out.println("symulacja");
		for (int i = 0; i < n; i++)
		{
			nextMove();
			// try
			// {
			// Thread.sleep(1000);
			// }
			// catch (InterruptedException e)
			// {
			// // TODO Auto-generated catch block
			// e.printStackTrace();
			// }
		}
	}

	private void nextMove()
	{
		clearIntensity();
		ArrayList<Point> listaZabronionych = new ArrayList<Point>();
//		System.out.println("car number: " + cars.size());
//		System.out.println("+++++++++++++++++++++++++++++++++");
		for (int i = cars.size() - 1; i >= 0; i--)
		{
			Car car = cars.get(i);

			// pobierz pozycje nastepnego punktu
			Point p = getNextPoint(car.getX(), car.getY(), car.getDirection());
//			System.out.println("samochod" + car.getX() + "," + car.getY());

			// jesli wyszlo za tablice to usun ten samochod i przejdz do analizy
			// kolejnego
			if (isOutOfTable(p))
			{
				carTable[car.getX()][car.getY()] = null;
				cars.remove(car);
//				System.out.println("samochod out of table");
				continue;
			}

			// sprawdz czy punkt jest wolny
			if (isPointFree(p) == false)
			{
				// jak zajety to nie pojedzie sie w tej iteracji
//				System.out.println("punkt zajety");
				continue;
			}

			// sprawdzenie czy nastepne jest skrzyzowanie
			if (isCrossing(p))
			{
				// jesli dopiero wjezdza na skrzyzowanie to wylosuj nowy
				// kierunek
				// wykona sie tylko bezposrednio przed skrzyzowaniem
				if (car.isDirectionChosen() == false)
				{
//					System.out.println("wybranie kierunku");
					car.setDirectionChosen(true);
					Direction d = chooseDirection(p, car.getDirection());
					car.setNewDirection(d);
//					tickTraffic(p, car.getDirection());
				}
//				System.out.println("na nastepnym skrzyzowanie");
				if (isRedLight(p, car.getDirection()))
				{
					//jesli jest bezposrednio przed skrzyzowaniem - nie wjezdza
					if (isCrossing(new Point(car.getX(), car.getY())) == false)
					{
//						System.out.println("czerwone swiatlo");
						continue;
					} 
					else // jesli juz jest na skrzyzowaniu to wyjedz bez wzgledu na swiatla
					{
//						System.out.println("wyjezdzam ze skrzyzowania");
					}
				} 
				else //zielone swiatlo
				{
//					jesli jest przed skrzyzowaniem
					if (isCrossing(new Point(car.getX(), car.getY()))==false)
					{
						if (getCarCount(p) > 1)
						{
							System.out.println("nie wjezdzam na skrzyzowanie");
							continue;
						}
						if(canExitCrossing(new Point(p),car.getDirection(),car.getNewDirection())==false)
						{
							System.out.println("NIE WJEZDZAM BO BYM NIE WYJECHAL");
							continue;
						}
					} 
//					System.out.println("zielone swiatlo");
				}
			} else// p nie jest skrzyzowaniem
			{
				car.setDirectionChosen(false);
			}

			//lista punktow z ktorych ruszyly sie samochody w tym wywolaniu
			if (listaZabronionych.contains(p))
			{
//				System.out.println("z listy zabronionych - nie wolno przesunac");
			} else
			{
				// mozna przesunac samochod
				listaZabronionych.add(new Point(car.getX(), car.getY()));
				carTable[car.getX()][car.getY()] = null;
				carTable[p.x][p.y] = car;
				car.setPoint(p);

				car.decrementCountTime();
//				System.out.println("przesunieto samochod");
//				System.out.println("samochod obecnie" + car.getX() + ","
//						+ car.getY());
			}

			// po dekrementacji do zera zmiana kierunku
			if (car.getCountTime() == 0)
			{
				car.changeDirection();
//				System.out.println("zmiana kierunku samochodu");
			}
		}
//		System.out.println("+++++++++++++++++++++++++++++++++");
		repaint();
	}

	private boolean canExitCrossing(Point p, Direction d, Direction newd)
	{
		//no kurde inaczej sie nie dalo
		Point nextP = new Point();
		if(d == Direction.UP)
		{
			if(newd == Direction.UP)
			{
				p.y -= 2;
				nextP = new Point(p);
				nextP.y-=1;
			}
			else if(newd == Direction.DOWN)
			{
				p.x-=1;
				p.y+=1;
				nextP = new Point(p);
				nextP.y+=1;
			}
			else if( newd == Direction.LEFT)
			{
				p.x-=2;
				p.y-=1;
				nextP = new Point(p);
				nextP.x-=1;
			}
			else if(newd== Direction.RIGHT)
			{
				p.x+=1;
				nextP = new Point(p);
				nextP.x+=1;
			}
		}
		else if(d == Direction.DOWN)
		{
			if(newd == Direction.UP)
			{
				p.x+=1;
				p.y-=1;
				nextP = new Point(p);
				nextP.y-=1;
			}
			else if(newd == Direction.DOWN)
			{
				p.y+=2;
				nextP = new Point(p);
				nextP.y+=1;
			}
			else if( newd == Direction.LEFT)
			{
				p.x-=1;
				nextP = new Point(p);
				nextP.x-=1;
			}
			else if(newd== Direction.RIGHT)
			{
				p.x+=2;
				p.y+=1;
				nextP = new Point(p);
				nextP.x+=1;
			}
		}
		else if( d == Direction.LEFT)
		{
			if(newd == Direction.UP)
			{
				p.y-=1;
				nextP = new Point(p);
				nextP.y-=1;
			}
			else if(newd == Direction.DOWN)
			{
				p.y+=2;
				p.x-=1;
				nextP = new Point(p);
				nextP.y+=1;
			}
			else if( newd == Direction.LEFT)
			{
				p.x-=2;
				nextP = new Point(p);
				nextP.x-=1;
			}
			else if(newd== Direction.RIGHT)
			{
				p.x+=1;
				p.y+=1;
				nextP = new Point(p);
				nextP.x+=1;
			}
		}
		else if(d== Direction.RIGHT)
		{
			if(newd == Direction.UP)
			{
				p.x+=1;
				p.y-=2;
				nextP = new Point(p);
				nextP.y-=1;
			}
			else if(newd == Direction.DOWN)
			{
				p.y+=1;
				nextP = new Point(p);
				nextP.y+=1;
			}
			else if( newd == Direction.LEFT)
			{
				p.x-=1;
				p.y-=1;
				nextP = new Point(p);
				nextP.x-=1;
			}
			else if(newd== Direction.RIGHT)
			{
				p.x+=2;
				nextP = new Point(p);
				nextP.x+=1;
			}
		}
		if(isPointFree(p)==false)
		{
			if(isPointFree(nextP)==false)
			{
				return false;
			}
			return true;
		}
		return true;
	}

	private Direction chooseDirection(Point p, Direction direction)
	{
		for (Crossing crossing : crossingTable)
		{
			// wylosuj kierunek w skrzyzowaniu, do ktorego nalezy punkt p
			if (crossing.thisCrossing(p))
			{
				return crossing.chooseDirection(direction);
			}
		}
		return direction;
	}

	private boolean isRedLight(Point p, Direction direction)
	{
		for (Crossing crossing : crossingTable)
		{
			if (crossing.thisCrossing(p))
			{
				if (crossing.getLight(direction) == Light.RED)
				{
					return true;
				}
			}
		}
		return false;
	}

	private boolean isCrossing(Point p)
	{
		for (Crossing crossing : crossingTable)
		{
			if (crossing.thisCrossing(p))
			{
				return true;
			}
		}
		return false;
	}

	private int getCarCount(Point p)
	{
		for (Crossing crossing : crossingTable)
		{
			if (crossing.thisCrossing(p))
			{
				return crossing.getCarCount(carTable);
			}
		}
		return 0;
	}

	private boolean isPointFree(Point p)
	{
		if (carTable[p.x][p.y] == null)
		{
			return true;
		}
		return false;
	}

	private boolean isOutOfTable(Point point)
	{
		// TODO Auto-generated method stub
		if (point.x < 0 || point.x >= SIZE || point.y < 0 || point.y >= SIZE)
			return true;
		return false;
	}

	// zwraca nastepny punkt
	private Point getNextPoint(int x, int y, Direction direction)
	{
		if (direction == Direction.UP)
		{
			return new Point(x, y - 1);
		} else if (direction == Direction.DOWN)
		{
			return new Point(x, y + 1);
		} else if (direction == Direction.LEFT)
		{
			return new Point(x - 1, y);
		} else if (direction == Direction.RIGHT)
		{
			return new Point(x + 1, y);
		} else
			return null;
	}

	public void paintComponent(Graphics g)
	{
		super.paintComponent(g);

		Graphics2D g2d = (Graphics2D) g;
		
		g2d.setColor(new Color(200, 250, 200));
		g2d.fillRect(0, 0, this.getWidth(), this.getHeight());

		//plansza
		for (int i = 0; i < 46; i++)
		{
			for (int j = 0; j < 46; j++)
			{
				if (onTheRoad(i) || onTheRoad(j))
				{
					g2d.setColor(Color.gray);
					g2d.fillRect(50 + 10 * i, 50 + 10 * j, 10, 10);
				} else
				{
					g2d.setColor(Color.darkGray);
					g2d.fillRect(50 + 10 * i, 50 + 10 * j, 10, 10);
				}
			}
		}
		//samochody
		for (Car car : cars)
		{
			g2d.setColor(car.getColor());
			g2d.fillOval(50 + car.getX() * 10, 50 + car.getY() * 10, 10, 10);
		}

		//swiatla
		for (Crossing crossing : crossingTable)
		{
			if (crossing.getLight(Direction.UP) == Light.RED)
			{
				g2d.setColor(Color.red);
				for (Point lightP : crossing.getLighsPositions(Direction.UP))
				{
					g2d.fillOval(50 + 10 * lightP.x, 50 + 10 * lightP.y, 10, 10);
				}
			} else
			{
				g2d.setColor(Color.green);
				for (Point lightP : crossing.getLighsPositions(Direction.UP))
				{
					g2d.fillOval(50 + 10 * lightP.x, 50 + 10 * lightP.y, 10, 10);
				}
			}

			if (crossing.getLight(Direction.LEFT) == Light.GREEEN)
			{
				g2d.setColor(Color.green);
				for (Point lightP : crossing.getLighsPositions(Direction.LEFT))
				{
					g2d.fillOval(50 + 10 * lightP.x, 50 + 10 * lightP.y, 10, 10);
				}
			} else
			{
				g2d.setColor(Color.red);
				for (Point lightP : crossing.getLighsPositions(Direction.LEFT))
				{
					g2d.fillOval(50 + 10 * lightP.x, 50 + 10 * lightP.y, 10, 10);
				}
			}
		}
	}

	private class ButtonListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			System.out.println("listener");

			for (int i = 0; i < 4; i++)
			{
				for (int j = 0; j < 3; j++)
				{
					if (e.getSource().equals(buttons[i][j]))
					{
						System.out.println(i + "," + j + "clicked");
						
						try
						{
							available.acquire();
						}
						catch (InterruptedException e1)
						{
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
						addCar(i, j);
						available.release();
						repaint();
					}
					;
				}
			}
		}
	}

	private void updateIntensity()
	{
		for(Car car : cars)
		{
//			System.out.println("updateIntensity");
			calculateCrossing(new Point(car.getX(),car.getY()),car.getDirection());
		}
	}
	
	private void calculateCrossing(Point point, Direction direction)
	{
//		System.out.println("calculate crossing");
		
		if(isCrossing(point))
			return;
		
		do
		{
			if(direction == Direction.UP)
			{
				point.y--;
			}
			else if( direction == Direction.DOWN)
			{
				point.y++;
			}
			else if( direction == Direction.LEFT)
			{
				point.x--;
			}
			else if( direction == Direction.RIGHT)
			{
				point.x++;
			}
		}
		while( isCrossing(point) == false && isOutOfTable(point) == false );
		
		if(isOutOfTable(point))
		{
			return;
		}
		for (int i = 0; i<crossingTable.length ; i++ )
		{
			if(crossingTable[i].thisCrossing(point))
			{
				if(direction == Direction.UP || direction == Direction.DOWN)
				{
					intensityTable[i][1]++;
					break;
				}
				else
				{
					intensityTable[i][0]++;
				}
			}
		}
			
	}
	
	private void clearIntensity()
	{
		for(int i =0 ; i<intensityTable.length; i++)
		{
			intensityTable[i][0] = 0;
			intensityTable[i][1] = 0;
		}
	}

	private void connectToServer(final String address) throws UnknownHostException, IOException
	{
		System.out.println("availablePermits: "+available.availablePermits());
		while(available.availablePermits()==0)
		{
			available.release();
		}
		readerThread = new Thread(new ReaderThread());
		readerThread.start();
	}

	private int[][] prepareIntensityTable()
	{
		return intensityTable;
	}

	private void setLights(LightsState tablica[])
	{
		System.out.println("Set Lights");
		for (int i = 0; i < tablica.length; i++)
		{
			crossingTable[i].setLight(tablica[i]);
		}
	}

	private void addCars(int procent)
	{
		Random r = new Random();
		int tmp;
		for (int i = 0; i < 4; i++)
		{
			for (int j = 0; j < 3; j++)
			{
				tmp = r.nextInt() % 100;
				if (tmp < 0)
					tmp *= -1;
				if (tmp < procent)
				{
					addCar(i, j);
				}
			}
		}
	}

	private void addCar(int i, int j)
	{
		int docelowyX = 0, docelowyY = 0;
		Direction d;
		if (i == 0)
		{
			docelowyY = 0;
			docelowyX = 10 + 12 * j;
			d = Direction.DOWN;
		} else if (i == 1)
		{
			docelowyY = SIZE - 1;
			docelowyX = 11 + 12 * j;
			d = Direction.UP;
		} else if (i == 2)
		{
			docelowyX = 0;
			docelowyY = 11 + 12 * j;
			d = Direction.RIGHT;
		} else
		// (i == 3)
		{
			docelowyX = SIZE - 1;
			docelowyY = 10 + 12 * j;
			d = Direction.LEFT;
		}


		if (isPointFree(new Point(docelowyX, docelowyY)))
		{
			carTable[docelowyX][docelowyY] = new Car(docelowyX, docelowyY, d);
			cars.add(carTable[docelowyX][docelowyY]);
		} else
		{
			System.out.println("wezel zajety");
		}
	}
	

	private class ReaderThread implements Runnable
	{
		/**
		 * Watek odczytujacy zdarzenia pochodzace z kontrolera
		 * 
		 */
		public void run()
		{
//			System.out.println("reader thread");
			try
			{
				clientSocket = new Socket(addressIp, PORT_NUMBER);
			}
			catch (UnknownHostException e)
			{
				// TODO Auto-generated catch block
				System.out.println("unknown host exception");
				e.printStackTrace();
			}
			catch (IOException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			while(true)
			{
				GETLIGHTSRequest lightsRequest = new GETLIGHTSRequest(clientSocket);
				lightsRequest.send();

				//odpowiedz od servera i ustawienie swiatel
				Response lightResponse = Response.getFrom(clientSocket);
				if (lightResponse instanceof GETLIGHTSResponse)
				{
//					System.out.println("lights response");
					if(((GETLIGHTSResponse) lightResponse).getLights() != null)
					{
//						opuszczenie semafora>>>>>>>>>>>>>>>>>>>>>>>>
						try
						{
							available.acquire();
						}
						catch (InterruptedException e1)
						{
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
						setLights(((GETLIGHTSResponse) lightResponse).getLights().getStates());
//						System.out.println("pelne swiatla");
						//zwolnienie semafora<<<<<<<<<<<<<<<<<<<<<<<<<<
						available.release();
					}
					else
					{
//						System.out.println("swiatla byly null");
					}
				}
				
//				opuszczenie semafora>>>>>>>>>>>>>>>>>>>>>>>>
				try
				{
					available.acquire();
				}
				catch (InterruptedException e1)
				{
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				//wykonanie kroku
				long t1 = System.currentTimeMillis();
				nextMove();
//				System.out.println("po nastepnym kroku");
				updateIntensity();
				addCars(6);
				long t2 = System.currentTimeMillis();
				System.out.println("Czas obliczen: "+(t2-t1));
				
				//wyslanie samochodow do serwera
				CarsInfo carsInfo = new CarsInfo(cars);
				SETCARSRequest scr = new SETCARSRequest(clientSocket, carsInfo);
				scr.send();
				
				//zwolnienie semafora<<<<<<<<<<<<<<<<<<<<<<<<<<
				available.release();
				
//				System.out.println("wyslano samochody");
				
				//potwierdzenie od serwera o otrzymaniu samochodow
				OKResponse okr = (OKResponse) Response.getFrom(clientSocket);
//				System.out.println("po odpowiedzi");

//				opuszczenie semafora>>>>>>>>>>>>>>>>>>>>>>>>
				try
				{
					available.acquire();
				}
				catch (InterruptedException e1)
				{
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}				
				//wyslanie natezenia ruchu
				IntensityInfo intensityInfo = new IntensityInfo(prepareIntensityTable());
				SETINTENSITYRequest intensityReq = new SETINTENSITYRequest(clientSocket, intensityInfo);
				intensityReq.send();
				//zwolnienie semafora<<<<<<<<<<<<<<<<<<<<<<<<<<
				available.release();
				
//				System.out.println("wyslano intensity");
				
				//potwierdzenie od serwera o otrzymaniu natezenia przez serwer
				okr.getFrom(clientSocket);
//				System.out.println("po odpowiedzi");
				
				try
				{
					Thread.sleep(250);
				}
				catch (InterruptedException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}//while
		}//run
	}//ReaderThread

}// koniec klasy
